home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / WINVCOLL.ZIP / WINTUTOR.ZIP / WININFO4.TXT < prev   
Text File  |  1996-02-09  |  9KB  |  221 lines

  1.  
  2.  
  3.                   Infection of Portable Executables
  4.                                 by
  5.                       Qark and Quantum [VLAD]
  6.  
  7.  
  8.   The portable executable format is used by Win32, Windows NT and Win95,
  9.   which makes it very popular and likely to become the dominant form of
  10.   executable sometime in the future.  The NE header used by Windows 3.11
  11.   is completely different to the PE header and the two should not be
  12.   confused.
  13.  
  14.   None of the techniques in this document have been tested on Windows NT
  15.   because no virus writer (we know) has access to it.
  16.    
  17.   At the bottom of this document is a copy of the PE format, which is not
  18.   easy to follow but is the only reference publicly available.  Turbo
  19.   Debugger 32 (TD32) is the debugger used during the research of this
  20.   text, but SoftIce'95 also does the job.
  21.  
  22.   Calling Windows 95 API
  23.   ──────────────────────
  24.  
  25.   A legitimate application calls win95 api by the use of an import
  26.   table.  The name of every API that the application wants to call is
  27.   put in the import table.  When the application is loaded, the data
  28.   needed to call the API is filled into the import table.  As was
  29.   explained in the win95 introduction (go read it), we cannot modify
  30.   this table due to Microsoft's foresight.
  31.  
  32.   The simple solution to this problem is to call the kernel directly.
  33.   We must completely bypass the Win95 calling stucture and go straight
  34.   for the dll entrypoint.
  35.  
  36.   To get the handle of a dll/exe (called a module) we can use the API
  37.   call GetModuleHandle and there are other functions to get the
  38.   entrypoint of a module - including a function to get the address of an
  39.   API, GetProcAddress.
  40.  
  41.   But this raises a chicken and egg question.  How do I call an API so I
  42.   can call API's, if I can't call API's ?  The solution is to call api
  43.   that we know are in memory - API that are in KERNEL32.DLL - by calling
  44.   the address that they are always located at.
  45.  
  46.   Some Code
  47.   ─────────
  48.  
  49.   A call to an API in a legitimate application looks like:
  50.  
  51.         call APIFUNCTIONNAME
  52. eg.     call CreateFileA
  53.  
  54.   This call gets assembled to:
  55.  
  56.         db 9ah          ; call
  57.         dd ????         ; offset into jump table
  58.  
  59.   The code at the jump table looks like:
  60.  
  61.         jmp far [offset into import table]
  62.  
  63.   The offset into the import table is filled with the address of the
  64.   function dispatcher for that API function.  This address is obtainable
  65.   with the GetProcAddress API.  The function dispatcher looks like:
  66.  
  67.         push function value
  68.         call Module Entrypoint
  69.  
  70.   There are API functions to get the entrypoint for any named module but
  71.   there is no system available to get the value of the function.  If we
  72.   are calling KERNEL32.DLL functions (of which are all the functions
  73.   needed to infect executables) then we need look no further than this
  74.   call.  We simply push the function value and call the module
  75.   entrypoint.
  76.  
  77.   Snags
  78.   ─────
  79.  
  80.   In the final stages of Bizatch we beta tested it on many systems.
  81.   After a long run of testing we found that the KERNEL32 module was
  82.   static in memory - exactly as we had predicted - but it was at a
  83.   different location from the "June Test Release" to the "Full August
  84.   Release" so we needed to test for this.  What's more, one function
  85.   (the function used to get the current date/time) had a different
  86.   function number on the June release than it did on the August release.
  87.   To compensate I added code that checks to see if the kernel is at one
  88.   of the 2 possible locations, if the kernel isn't found then the virus
  89.   doesn't execute and control is returned to the host.
  90.  
  91.   Addresses and Function Numbers
  92.   ──────────────────────────────
  93.  
  94.   For the June Test Release the kernel is found at 0BFF93B95h
  95.   and for the August Release the kernel is found at 0BFF93C1Dh
  96.  
  97.   Function              June            August
  98.   ──────────────────────────────────────────────────
  99.   GetCurrentDir       BFF77744         BFF77744
  100.   SetCurrentDir       BFF7771D         BFF7771D
  101.   GetTime             BFF9D0B6         BFF9D14E
  102.   MessageBox          BFF638D9         BFF638D9
  103.   FindFile            BFF77893         BFF77893
  104.   FindNext            BFF778CB         BFF778CB
  105.   CreateFile          BFF77817         BFF77817
  106.   SetFilePointer      BFF76FA0         BFF76FA0
  107.   ReadFile            BFF75806         BFF75806
  108.   WriteFile           BFF7580D         BFF7580D
  109.   CloseFile           BFF7BC72         BFF7BC72
  110.  
  111.  
  112.   Using a debugger like Turbo Debugger 32bit found in Tasm 4.0, other
  113.   function values can be found.
  114.  
  115.   Calling Conventions
  116.   ───────────────────
  117.  
  118.   Windows 95 was written in C++ and Assembler, mainly C++.  And although
  119.   C calling conventions are just as easy to implement, Microsoft didn't
  120.   use them.  All API under Win95 are called using the Pascal Calling
  121.   Convention.  For example, an API as listed in Visual C++ help files:
  122.  
  123.         FARPROC GetProcAddress(
  124.                 HMODULE  hModule,   // handle to DLL module
  125.                         LPCSTR  lpszProc        // name of function
  126.         );
  127.  
  128.   At first it would be thought that all you would need to do is push the
  129.   handle followed by a pointer to the name of the function and call the
  130.   API - but no.  Due to Pascal Calling Convention, the parameters need
  131.   to be pushed in reverse order:
  132.  
  133.           push offset lpszProc
  134.           push dword ptr [hModule]
  135.           call GetProcAddress
  136.  
  137.   Using a debugger like Turbo Debugger 32bit we can trace the call (one
  138.   step) and follow it to the kernel call as stated above.  This will
  139.   allow us to get the function number and we can do away with the need
  140.   for an entry in the import table.
  141.  
  142.  
  143.   Infection of the PE Format
  144.   ──────────────────────────
  145.  
  146.   Finding the beginning of the actual PE header is the same as for NE
  147.   files, by checking the DOS relocations for 40h or more, and seeking to
  148.   the dword pointed to by 3ch.  If the header begins with a 'NE' it is a
  149.   Windows 3.11 executable and a 'PE' indicates a Win32/WinNT/Win95 exe.
  150.  
  151.   Within the PE header is 'the object table', which is the most important
  152.   feature of the format with regards to virus programming.  To append code
  153.   to the host and redirect initial execution to the virus it is necessary to
  154.   add another entry to the 'object table'.  Luckily, Microsoft is obsessed
  155.   with rounding everything off to a 32bit boundary, so there will be room
  156.   for an extra entry in the empty space most of the time, which means it
  157.   isn't necessary to shift any of the tables around.
  158.  
  159.   
  160.   A basic overview of the PE infection:
  161.  
  162.         Locate the offset into the file of the PE header
  163.         Read a sufficient amount of the PE header to calculate the full size
  164.         Read in the whole PE header and object table
  165.         Add a new object to the object table
  166.         Point the "Entry Point RVA" to the new object
  167.         Append virus to the executable at the calculated physical offset
  168.         Write the PE header back to the file
  169.  
  170.  
  171.   To find the object table:
  172.    The 'Header Size' variable (not to be confused with the 'NT headersize')
  173.    is the size of the DOS header, PE header and object table, combined.
  174.    To read in the object table, read in from the start of the file for
  175.    headersize bytes.
  176.  
  177.    The object table immediately follows the NT Header. The 'NTheadersize'
  178.    value, indicates how many bytes follow the 'flags' field.  So to work
  179.    out the object table offset, get the NTheaderSize and add the offset
  180.    of the flags field (24).
  181.  
  182.   Adding an object:
  183.    Get the 'number of objects' and multiply it by 5*8 (the size of an object
  184.    table entry).  This will produce the offset of the space within which
  185.    the new virus object table entry can be placed.
  186.    The data for the virus' object table entry needs to be calculated using
  187.    information in the previous (host) entry.
  188.  
  189.    RVA             = ((prev RVA + prev Virtual Size)/OBJ Alignment+1)
  190.                                                                *OBJ Alignment
  191.    Virtual Size    = ((size of virus+buffer any space)/OBJ Alignment+1)
  192.                                                                *OBJ Alignment
  193.    Physical Size   = (size of virus/File Alignment+1)*File Alignment
  194.    Physical Offset = prev Physical Offset + prev Physical Size
  195.    Object Flags    = db 40h,0,0,c0h
  196.    Entrypoint RVA  = RVA
  197.    
  198.    Increase the 'number of objects' field by one.
  199.  
  200.    Write the virus code to the 'physical offset' that was calculated, for
  201.    'physical size' bytes.
  202.  
  203.  
  204.   Notes
  205.   ─────
  206.  
  207.   Microsoft no longer includes the PE header information in their developers
  208.   CDROMs.  It is thought that this might be to make the creation of
  209.   viruses for Win95 less likely.  The information contained in the next
  210.   article was obtained from a Beta of the Win32 SDK CDROM.
  211.  
  212.  
  213.   Tools
  214.   ─────
  215.  
  216.   There are many good books available that supply low level Windows 95
  217.   information.  "Unauthorized Windows 95", although not a particularly
  218.   useful book (it speaks more of DOS/Windows interaction), supplies
  219.   utilities on disk and on their WWW site that are far superior to the
  220.   ones that we wrote to research Win95 infection.
  221.